package com.xzzz.irda.auth.core.permission;

import cn.hutool.core.collection.CollectionUtil;
import com.xzzz.irda.auth.core.authorization.AuthContext;
import com.xzzz.irda.auth.core.exception.AuthException;
import com.xzzz.irda.auth.core.exception.AuthRCode;
import com.xzzz.irda.auth.core.AuthBaseProperties;
import com.xzzz.common.base.util.ServletUtil;
import com.xzzz.common.base.util.spring.AntPathMatcherUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 权限切面
 * 注解: {@link PermAuth}
 *
 * @author wangyf
 *
 */
@Slf4j
@Aspect
public class PermAuthAspect {

    @Autowired
    private AuthBaseProperties propertiesConfiguration;

    /**
     * 类切点, 类与方法都有时都会校验
     *
     * @param joinPoint 切入点调用
     * @param permAuth 方法注解
     */
    @Before("@within(permAuth)")
    public void beforeCheckClass(JoinPoint joinPoint, PermAuth permAuth) {
        beforeCheck(joinPoint, permAuth);
    }

    /**
     * 方法切点, 类与方法都有时都会校验
     *
     * @param joinPoint 切入点调用
     * @param permAuth 方法注解
     */
    @Before("@annotation(permAuth)")
    public void beforeCheckMethod(JoinPoint joinPoint, PermAuth permAuth) {
        beforeCheck(joinPoint, permAuth);
    }

    /**
     * 上下文中检查是否具有对应权限
     *
     * @param joinPoint 切入点调用
     * @param permAuth 方法注解
     */
    private void beforeCheck (JoinPoint joinPoint, PermAuth permAuth) {
        HttpServletRequest httpServletRequest = ServletUtil.getRequest();
        if (httpServletRequest == null) {
            throw new IllegalArgumentException("未获取到请求信息");
        }
        String uri = httpServletRequest.getRequestURI();

        // 请求在白名单中
        boolean isWhiteRequest = false;
        for (String pattern : propertiesConfiguration.getWhiteList()) {
            if (AntPathMatcherUtil.match(pattern, uri)) {
                isWhiteRequest = true;
                break;
            }
        }

        // 非白名单请求则判断请求权限, 白名单请求不校验权限因为无法获取上下文
        if (!isWhiteRequest){
            List<String> perms = AuthContext.getContext().getPermissions();

            if (CollectionUtil.isEmpty(perms)) {
                throw new AuthException(AuthRCode.PERMISSION_DENIED);
            }

            // 查看请求用户是否有当前路径的请求权限
            String perm = permAuth.value();
            boolean hasPerm = perms.stream()
                    .filter(StringUtils::hasText)
                    .anyMatch(x -> PatternMatchUtils.simpleMatch(perm, x));

            log.debug("[AUTHORIZ] PerAspect >> 是否具有[{}]权限: {}",perm,hasPerm);

            if (!hasPerm) {
                throw new AuthException(AuthRCode.PERMISSION_DENIED);
            }
        }

    }

}
